package com.dc.datacollect.utils;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

public class HttpRequestUtils {
//    public static abstract class BodyType extends File implements UnaryOperation {
//
//        public BodyType(String pathname) {
//            super(pathname);
//        }
//    }
    private static CloseableHttpClient httpClient;

    /**
     * 获取支持安全协议的连接工程
     * @return
     */
    private static ConnectionSocketFactory getConnectionSocketFactory() {
        try {
            SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
            // 是否信任url
            sslContextBuilder.loadTrustMaterial(null, (x509Certificates, s) -> true);
            SSLContext sslContext = sslContextBuilder.build();
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                    sslContext,
                    new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"},
                    null,
                    NoopHostnameVerifier.INSTANCE);
            return sslConnectionSocketFactory;
        }catch (Exception e) {
            return null;
        }
    }
    static {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", getConnectionSocketFactory())
                .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
        cm.setMaxTotal(100);
        cm.setDefaultMaxPerRoute(10);

        httpClient = HttpClients.custom()
                .setConnectionManager(cm)
                .build();
    }

    @Data
    public static class RequestData {
        private String url;
        private Map<String,String> header;
        private Map<String,String> query;
        private Map<String,Object> body;
    }

    @Data
    public static class Response {
        private Integer status;
        private Header[] headers;
        private HttpResponse httpResponse;

        public Response(HttpResponse httpResponse) {
            this.httpResponse = httpResponse;
            this.status = httpResponse.getStatusLine().getStatusCode();
            this.headers = httpResponse.getAllHeaders();
        }

        public String getBody() {
            try {
                return EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
            }catch (Exception e) {
                return null;
            }
        }
        public void save(String path) throws IOException {
            HttpEntity entity = httpResponse.getEntity();
            InputStream imageContent = entity.getContent();
            FileOutputStream imageFile = new FileOutputStream(path);
            byte[] buffer = new byte[4096];
            int bytesRead = -1;

            while ((bytesRead = imageContent.read(buffer)) != -1) {
                imageFile.write(buffer, 0, bytesRead);
            }
            imageFile.flush();
            imageFile.close();
            imageContent.close();
        }
    }
    public static class RequestExecute {
        private HttpRequestBase httpRequestBase;

        private RequestConfig.Builder configBuilder;

        public RequestExecute(HttpRequestBase httpRequestBase) {
            this.httpRequestBase = httpRequestBase;
            // 进行默认配置
            configBuilder = RequestConfig.custom()
                // tcp 3次握手的时间上限
                .setConnectTimeout(2500)
                // 连接建立后得到响应后的时间
                .setSocketTimeout(3500)
                // 从连接池中获取连接的超时时间
                .setConnectionRequestTimeout(2000);

        }
        public RequestExecute config(Function<RequestConfig.Builder,RequestConfig> consumer) {
            RequestConfig config = consumer.apply(configBuilder);
            httpRequestBase.setConfig(config);
            return this;
        }

        public Response send() throws IOException {
            HttpResponse httpResponse = httpClient.execute(httpRequestBase);
            if (httpResponse == null) {
                throw new IllegalArgumentException("在将RawResponse(持有HttpResponse)加工为Response时出现，原因是最原始的HttpResponse对象为空。");
            }
            return new Response(httpResponse);
        }
        public Response proxySend(String host,int port) throws IOException {
            HttpHost httpHost = new HttpHost(host,port);
            RequestConfig requestConfig = RequestConfig.custom().setProxy(httpHost).build();
            httpRequestBase.setConfig(requestConfig);
            return send();
        }

    }
    public static class Builder {


        private RequestData requestData = new RequestData();


        public Builder(String url) {
            this.requestData.setUrl(url);
        }

        public Builder header(Map<String,String> header) {
            this.requestData.setHeader(header);
            return this;
        }
        public Builder query(Map<String,String> query) {
            this.requestData.setQuery(query);
            return this;
        }
        public Builder body(Map<String,Object> body) {
            this.requestData.setBody(body);
            return this;
        }



        private String getFullUrl() {
            Map<String, String> queryMap = this.requestData.query;
            try {
                URIBuilder uriBuilder = new URIBuilder(this.requestData.url);
                if (queryMap != null) {
                    for (String key : queryMap.keySet()) {
                        uriBuilder.setParameter(key, queryMap.get(key));
                    }
                }
                return uriBuilder.build().toString();
            }catch (Exception e) {
                return requestData.url;
            }
        }
        private HttpRequestBase injectHeader(HttpRequestBase httpRequestBase) {
            Map<String, String> headerMap = this.requestData.header;
            if (headerMap != null) {
                for (String key : headerMap.keySet()) {
                    httpRequestBase.setHeader(key, headerMap.get(key));
                }
            }
            return httpRequestBase;
        }


        public RequestExecute buildFromPost() {
            try {
                Map<String, Object> body = this.requestData.body;
                HttpPost httpPost = new HttpPost(getFullUrl());
                injectHeader(httpPost);

                MultipartEntityBuilder builder = MultipartEntityBuilder.create();
                body.keySet().forEach(key->{
                    Object value = body.get(key);
                    if (value instanceof File) {
                        builder.addBinaryBody(key,(File) value);
                    }else if(value instanceof String){
                        builder.addPart(key,new StringBody((String) value, ContentType.create("text/plain", Consts.UTF_8)));
                    }
                });
                httpPost.setEntity(builder.build());
                return new RequestExecute(httpPost);
            }catch (Exception e) {

            }
            return null;
        }
        public RequestExecute buildJsonPost() throws UnsupportedEncodingException {
            HttpPost httpPost = new HttpPost(getFullUrl());
            injectHeader(httpPost);
            // json字符串
            StringEntity jsonEntity = new StringEntity(JSONObject.toJSONString(requestData.body),"utf-8");
            // 给Entity设置Content-Type
            jsonEntity.setContentType(new BasicHeader("Content-Type", "application/json; charset=utf-8"));
            httpPost.setEntity(jsonEntity);
            return new RequestExecute(httpPost);
        }

        public RequestExecute buildGet() {
            try {
                HttpRequestBase httpGet = new HttpGet(getFullUrl());
                injectHeader(httpGet);
                return new RequestExecute(httpGet);
            }catch (Exception e) {
                System.err.println("构建GET请求失败！");
                e.printStackTrace();
            }
            return null;
        }
    }

    public static Builder Builder(String url) {
        return new Builder(url);
    }


    public static void main(String[] args) throws IOException {

//        HttpRequestUtils.Builder("https://img-blog.csdnimg.cn/df95cea978ae4002a91d49c0ad8cba02.png")
//                .body(body) // Map<String,Object>
//                .query(query) // Map<String,String>
//                .header(header) // Map<SString,String>
//                .buildGet().config(cb->cb.setConnectTimeout(2).build()).send().getBody()/save();


    }
}
